//
//  VideoPlayerManager.swift
//  视频管理器，封装了常用功能，播放，暂停等功能
//  目的是对外只提供必要的接口
//  内部可以自由重构，换其他框架
//  这里面的大部分逻辑和音乐播放差不多
//  可以重构到一起
//
//  Created by smile on 2019/5/27.
//  Copyright © 2019 ixuea. All rights reserved.
//

import Foundation

//导入系统媒体框架
import MediaPlayer

class VideoPlayerManager:NSObject {
    // 单例设计模式
    static var shared=VideoPlayerManager()
    
    /// 代理
    var delegate:VideoPlayerDelegate? {
        didSet {
            
            if let _ = self.delegate {
                //有回调函数就执行
                //启动进度更新
                if self.isPlaying() {
                    //正在播放
                    //启动进度通知
                    startPublishProgress()
                }
            }else{
                //没有回调函数就停止
                stopPublishProgress()
            }
            
        }
    }
    
    /// 播放器
    var player:AVPlayer!
    
    /// 显示视频的视图层
    var playLayer:AVPlayerLayer!
    
    /// 正在播放的音乐
    var data:Video?
    
    /// 进度更新返回的对象
    /// 取消进度更新要用到它
    var playTimeObserver:Any?
    
    /// 播放状态
    var status:PlayStatus = .none
    
    /// 初始化
    override init() {
        super.init()
        player=AVPlayer.init()
        
        //创建显示视频图像的控件
        playLayer = AVPlayerLayer(player: player)
        
        //完全显示
        //但会有黑边
        playLayer.videoGravity = .resizeAspect
    }
    
    func initListeners() {
        //KVO方式监听播放状态
        //KVC:Key-Value Coding,另一种获取对象字段的值，类似字典
        //KVO:Key-Value Observing,建立在KVC基础上，能够观察一个字段值的改变
        player.currentItem?.addObserver(self, forKeyPath: MusicPlayerManager.STATUS, options: .new, context: nil)
        
        //缓冲进度
        player.currentItem?.addObserver(self, forKeyPath: MusicPlayerManager.LOADED_TIME_RANGES, options: .new, context: nil)

        //播放结束事件
        //        NotificationCenter.default.addObserver(self, forKeyPath: <#T##String#>, options: NSKeyValueObservingOptions, context: <#T##UnsafeMutableRawPointer?#>)
        NotificationCenter.default.addObserver(self, selector: #selector(onComplete(notification:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
    }
    
    /// KVO方式监听回调
    ///
    /// - Parameters:
    ///   - keyPath: <#keyPath description#>
    ///   - object: <#object description#>
    ///   - change: <#change description#>
    ///   - context: <#context description#>
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print("MusicPlayerManager observeValue:\(keyPath)")
        
        //判断监听的字段
        //因为可以监听多个字段
        if MusicPlayerManager.STATUS==keyPath {
            //播放相关状态
            switch player.status {
            case .readyToPlay:
                //准备播放
                self.data!.duration=Float(CMTimeGetSeconds(player.currentItem!.asset.duration))
                print("MusicPlayerManager duration:\(self.data!.duration)")
                
                //回调代理
                delegate?.onPrepared(data!)

                break
            case .failed:
                //播放失败
                let error=player.error
                
                print("MusicPlayerManager failed:\(error)")
                status = .error
                delegate?.onError(self.data!, error)
                break
            default:
                //未知转态
                print("MusicPlayerManager unknown")
                break
            }
        }else if MusicPlayerManager.LOADED_TIME_RANGES == keyPath {
            //缓冲相关
            let timeRanges = player.currentItem?.loadedTimeRanges
            
            //本次缓冲的时间范围
            let timeValue=timeRanges!.first!.timeRangeValue
            
            //缓冲总长度
            let totalLoadTime = CMTimeGetSeconds(timeValue.start)+CMTimeGetSeconds(timeValue.duration)
            
            //计算缓冲百分比例
            let loadPercent=totalLoadTime/Double(data!.duration)
            
            print("VideoPlayerManager loadPercent:\(loadPercent)")

        }
        
    }
    
    /// 移除监听器
    func removeListeners() {
        player.currentItem?.removeObserver(self, forKeyPath: MusicPlayerManager.STATUS)
        
        //缓冲进度
        player.currentItem?.removeObserver(self, forKeyPath: MusicPlayerManager.LOADED_TIME_RANGES)
        
        NotificationCenter.default.removeObserver(self)
    }
    
    /// 播放完成回调方法
    ///
    /// - Parameter notification: <#notification description#>
    @objc func onComplete(notification:Notification) {
        delegate?.onComplete(data!)
    }
    
    /// 播放
    ///
    /// - Parameters:
    ///   - uri: <#uri description#>
    ///   - video: <#video description#>
    func play(_ uri:String,_ video:Video) {
        status = .playing
        
        self.data=video
        
        var url:URL!
        if uri.hasPrefix("http") {
            //网络地址
            url=URL(string: uri)
        } else {
            //本地地址
            url=URL(fileURLWithPath: uri)
        }
        
        /// 创建一个播放Item
        let playerItem = AVPlayerItem(url: url)
        
        //替换到原来的
        player.replaceCurrentItem(with: playerItem)
        
        //播放
        player.play()
        
        //设置监听器
        //因为监听器是针对Item
        //所以播放新的Item要重新设置
        initListeners()
        
        //回调代理
        delegate?.onPlaying(data!)
        
        //启动进度通知
        startPublishProgress()
    
    }
    
    
    /// 是否在播放
    ///
    /// - Returns: <#return value description#>
    func isPlaying() -> Bool {
        return status == .playing
    }
    
    /// 暂停
    func pause() {
        status = .pause
        
        //移除监听器
        removeListeners()
        
        //播放器暂停
        player.pause()
        
        //回调代理
        delegate?.onPaused(data!)
        
        //通知通知进度
        stopPublishProgress()
    }
    
    /// 继续播放
    ///
    /// - Returns: <#return value description#>
    func resume() {
        status = .playing
        
        //设置监听器
        initListeners()
        
        //播放
        player.play()
        
        delegate?.onPlaying(data!)
        
        startPublishProgress()
    }
    
    /// 移动到指定位置播放
    ///
    /// - Parameter progress: <#progress description#>
    func seekTo(_ progress:Float) {
        let positionTime=CMTime(seconds: Double(progress), preferredTimescale: 1)
        
        player.seek(to: positionTime)
        
    }
    
    /// 是否单曲循环
    ///
    /// - Parameter looping: <#looping description#>
    func setLooping(_ looping:Bool) {
        
    }
    
    /// 销毁
    func destroy() {
        
    }
    
    /// 启动播放进度通知
    func startPublishProgress() {
        if let _ = playTimeObserver {
            //已经启动了
            return
        }
        
        //视频播放1秒钟回调一次就行了
        playTimeObserver=player.addPeriodicTimeObserver(forInterval: CMTime(value: CMTimeValue(1), timescale: 1), queue: DispatchQueue.main) { time in
            
            //当前播放的时间
            self.data!.progress=Float(CMTimeGetSeconds(time))
            
            print("VideoPlayerManager startPublishProgress:\(self.data!.progress)")
            
            guard let delegate = self.delegate else {
                //如果没有了回调函数就停止定时器
                self.stopPublishProgress()
                return
            }
            
            //有回调函数就执行
            delegate.onProgress(data: self.data!, progress: self.data!.progress, duration: self.data!.duration)
            
        }
    }
    
    /// 停止进度通知
    func stopPublishProgress() {
        if let playTimeObserver = playTimeObserver {
            player.removeTimeObserver(playTimeObserver)
            self.playTimeObserver=nil
        }
        
    }
    
}

/// 播放器代理
/// 可以将音乐播放器管理器的代理重构
protocol VideoPlayerDelegate: NSObjectProtocol {
    
    /// 进度回调
    ///
    /// - Parameters:
    ///   - data: <#data description#>
    ///   - progress: <#progress description#>
    ///   - duration: <#duration description#>
    func onProgress(data:Video,progress:Float,duration:Float)
    
    /// 暂停了播放
    ///
    /// - Parameter data: <#data description#>
    func onPaused(_ data:Video)
    
    /// 正在播放
    ///
    /// - Parameter data: <#data description#>
    func onPlaying(_ data:Video)
    
    /// 播放器准备完毕；可以获取到音乐市场
    ///
    /// - Parameter data: <#data description#>
    func onPrepared(_ data:Video)
    
    /// 播放发生了错误
    ///
    /// - Parameter data: <#data description#>
    func onError(_ data:Video,_ error:Error?)
    
    
    /// 播放完毕了
    ///
    /// - Parameter data: <#data description#>
    func onComplete(_ data:Video)
}
